﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
//Qt headers
#include <QPainter>
#include <QStyle>
#include <QStyleOption>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QPushButton>
#include <QFrame>
#include <QLineEdit>
#include <QComboBox>
#include <QScrollArea>
#include <QHeaderView>
#include <QScrollBar>
#include <QLabel>
#include <QJsonObject>

#include "GnufMessageBoardInterface.h"

// custom headers
#include "ProjectComponentEditingPage.h"
#include "BottomLineTab.h"
#include "Gac3DViewer.h"
#include "PathUtils.h"
#include "LegendEditingCard.h"
#include "ILegend.h"
#include "EditingParametersTableView.h"
#include "EditingParametersTableModel.h"
#include "IParameter.gcs.h"
#include "ParametersEditingCard.h"
#include "DrawerChest.h"
#include "CustomScroller.h"
#include "CustomReply.h"
#include "ISpecification.h"
#include "EditingProjectComponentContext.h"
#include "LegendChoosingDialog.h"
#include "StandardParametersChoosingDialog.h"
#include "SpecificationAddingDialog.h"
#include "SpecificationRenamingDialog.h"
#include "IParameterDefinition.gcs.h"
#include "ProjectCloudComponentService.h"
#include "IProjectComponent.h"
#include "ProjectLoadedComponentService.h"
#include "IGmepGcsProjectManager.h"
#include "SavingEditingProjectComponentDialog.h"
#include "BnufBulletin.h"
#include "ICategory.h"
#include "AppService.h"
#include "ProjectComponentExistingCheck.h"
#include "Permission.h"
#include "PermissionWatcher.h"
#include "SyncLocalProjectComponentWorkflow.h"
#include "UIService.h"
#include "GcsMainWindow.h"
#include "GbmpNew.h"
#include "TranslatorManager.h"
#include "NotificationUtils.h"

#include "QtFormNullValidator.h"
#include "QtFormValueValidator.h"
#include "GmepRecordTimeUtils.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h" 

namespace gmepgcs
{
    ProjectComponentEditingPage::ProjectComponentEditingPage(QWidget *parent, bool isPrivateEnv)
        :QWidget(parent),
        m_border(2, 2, 2, 2),
        m_borderColor(59, 132, 255, 255),
        m_widthOfParameterPanel(431),
        m_pGac3DViewer(nullptr),
        m_context(nullptr),
        m_bSwitchCurrentSpecificationTo(true),
        m_isByCommandShow(false),
        m_isPrivateEnv(isPrivateEnv)
    {
        InitUI();
    }

    ProjectComponentEditingPage::~ProjectComponentEditingPage()
    {
    }

    void ProjectComponentEditingPage::CheckIn(
        const std::wstring &projectId,
        const std::wstring &enterpriseId,
        const std::wstring &componentId, 
        const int32_t &componentVersion,
        const std::wstring &componentName)
    {
        Resume();

        Prepare(projectId, enterpriseId, componentId, componentVersion, componentName);

        // 初始认为名称合法
        DBG_WARN_AND_RETURN_VOID_UNLESS(m_pLeComponentName, L"m_pLeComponentName为空", L"GMEP", L"2024-01-30");
        m_pLeComponentName->setStyleSheet("");

    }
    
    void ProjectComponentEditingPage::SetIsByCommandShow(bool bIsByCommandShow)
    {
        m_isByCommandShow = bIsByCommandShow;
        UpdateVisableByIsCommand();
    }

    void ProjectComponentEditingPage::SetComponentCurrentFamilyTypeName(const std::wstring &familyTypeName)
    {
        if (m_pCbbSpec)
        {
            m_pCbbSpec->setCurrentText(QString::fromStdWString(familyTypeName));
        }
    }

    void ProjectComponentEditingPage::paintEvent(QPaintEvent * event)
    {
        QStyleOption opt;

        opt.init(this);
        QPainter p(this);
        if(style() != nullptr)
            style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);

        QWidget::paintEvent(event);

        if (event)
        {
            QPainter painter(this);

            // draw border
            if (m_border.left())
            {
                painter.setPen(QPen(m_borderColor, m_border.left()));
                QPointF offset(m_border.left() / 2, 0);
                painter.drawLine(rect().bottomLeft() + offset, rect().topLeft() + offset);
            }
            if (m_border.top())
            {
                painter.setPen(QPen(m_borderColor, m_border.top()));
                QPointF offset(0, m_border.top() / 2);
                painter.drawLine(rect().topLeft() + offset, rect().topRight() + offset);
            }
            if (m_border.right())
            {
                painter.setPen(QPen(m_borderColor, m_border.right()));
                painter.drawLine(rect().topRight(), rect().bottomRight());
            }
            if (m_border.bottom())
            {
                painter.setPen(QPen(m_borderColor, m_border.bottom()));
                painter.drawLine(rect().bottomRight(), rect().bottomLeft());
            }
        }
    }

    void ProjectComponentEditingPage::InitUI()
    {
        // 底部按钮区
        QLayout *pLayoutOperationButtons = InitBottomButtonsRegion();

        // 名称和分类区
        QLayout *pLayoutNameAndCategory = InitComponentNameAndCategoryRegion();

        // 3D预览和图例区
        QHBoxLayout *pLayout3DViewerAndOthers = NEW_AS_QT(QHBoxLayout);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pLayout3DViewerAndOthers != nullptr, L"pLayout3DViewerAndOthers为空", L"GMEP", L"2024-01-30");
        pLayout3DViewerAndOthers->setContentsMargins(16, 8, 16, 16);
        pLayout3DViewerAndOthers->setSpacing(0);

        BottomLineTab *pTab3DViewerAndOthers = NEW_AS_QT(BottomLineTab);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pTab3DViewerAndOthers != nullptr, L"pTab3DViewerAndOthers为空", L"GMEP", L"2024-01-30");
        pTab3DViewerAndOthers->setObjectName("ViewerJumper");
        pTab3DViewerAndOthers->SetShowSplitterLine(true);
        pLayout3DViewerAndOthers->addWidget(pTab3DViewerAndOthers);

        // 3D预览
        m_pGac3DViewer = NEW_AS_QT(Gac3DViewer,this);
        DBG_WARN_AND_RETURN_VOID_UNLESS(m_pGac3DViewer != nullptr, L"m_pGac3DViewer为空", L"GMEP", L"2024-01-30");
        m_pGac3DViewer->setObjectName("3DViewer");
        pTab3DViewerAndOthers->AddTabItem(QString::fromStdWString(GBMP_TR(L"3D预览")), m_pGac3DViewer);
       
        // 仅机电显示图例编辑页
        if (AppService::Get()->IsGmep())
        {
            // 图例区
            QWidget * pWgtLegends = InitLegendCardsRegion();
            if (pWgtLegends)
            {
                pWgtLegends->setObjectName("LegendPanel");
                pTab3DViewerAndOthers->AddTabItem(QString::fromStdWString(GBMP_TR(L"图例")), pWgtLegends);
            }
        }
        
        // 左上整体区域
        QVBoxLayout *pHLayoutTopLeftRegion = NEW_AS_QT(QVBoxLayout);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pHLayoutTopLeftRegion != nullptr, L"pHLayoutTopLeftRegion为空", L"GMEP", L"2024-01-30");
        pHLayoutTopLeftRegion->setContentsMargins(0, 0, 0, 0);
        pHLayoutTopLeftRegion->setSpacing(0);
        pHLayoutTopLeftRegion->addLayout(pLayoutNameAndCategory);
        pHLayoutTopLeftRegion->addLayout(pLayout3DViewerAndOthers);

        QFrame *pFrameTopLeftRegion = NEW_AS_QT(QFrame);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pFrameTopLeftRegion != nullptr, L"pFrameTopLeftRegion为空", L"GMEP", L"2024-01-30");
        pFrameTopLeftRegion->setObjectName("TopLeftRegionFrame");
        pFrameTopLeftRegion->setStyleSheet("QFrame#TopLeftRegionFrame{"
            "border-right:1px solid rgba(189, 199, 213, 255);"
            "}"
        );
        pFrameTopLeftRegion->setLayout(pHLayoutTopLeftRegion);
           
        // 规格区
        QLayout *pLayoutSpecs = InitSpecificationsRegion();

        BottomLineTab *pTabParameters = NEW_AS_QT(BottomLineTab);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pTabParameters != nullptr, L"pTabParameters为空", L"GMEP", L"2024-01-30");
        pTabParameters->setObjectName("ParametersTab");
        pTabParameters->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
        pTabParameters->setContentsMargins(0, 16, 2, 0);
        pTabParameters->SetHeaderBackgorund(QColor(217, 221, 228, 255));        
        
        // 几何参数
        QWidget *pWgtGeoParameters = InitGeometryParametersRegion();
        if (pWgtGeoParameters)
        {
            pWgtGeoParameters->setObjectName("GeoParametersWidget");
            pTabParameters->AddTabItem(QString::fromStdWString(GBMP_TR(L"几何参数")), pWgtGeoParameters);
        }

        // 产品参数
        QWidget *pWgtProdParameters = InitProductParametersRegion();
        if (pWgtProdParameters)
        {
            pWgtProdParameters->setObjectName("ProductPropertyWidget");
            pTabParameters->AddTabItem(QString::fromStdWString(GBMP_TR(L"产品属性")), pWgtProdParameters);
        }

        // 右上区域整体
        QVBoxLayout *pVLayoutParametersAndOthers = NEW_AS_QT(QVBoxLayout);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pVLayoutParametersAndOthers != nullptr, L"pVLayoutParametersAndOthers为空", L"GMEP", L"2024-01-30");
        pVLayoutParametersAndOthers->setContentsMargins(0, 0, 0, 0);
        pVLayoutParametersAndOthers->setSpacing(0);
        pVLayoutParametersAndOthers->addLayout(pLayoutSpecs);
        pVLayoutParametersAndOthers->setAlignment(pLayoutSpecs, Qt::AlignTop);
        pVLayoutParametersAndOthers->addWidget(pTabParameters);        

        QFrame *pFrameParametersAndOthers = NEW_AS_QT(QFrame);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pFrameParametersAndOthers != nullptr, L"pFrameParametersAndOthers为空", L"GMEP", L"2024-01-30");
        pFrameParametersAndOthers->setObjectName("PropertiesFrame");
        pFrameParametersAndOthers->setFixedWidth(m_widthOfParameterPanel);
        pFrameParametersAndOthers->setObjectName("ParametersAndOthersFrame");
        pFrameParametersAndOthers->setStyleSheet("QFrame#ParametersAndOthersFrame{"
            "border:1px solid rgba(189, 199, 213, 255);"
            "border-right:none;"
            "border-top:none;"
            "border-bottom:none;"
            "}"
        );
        pFrameParametersAndOthers->setLayout(pVLayoutParametersAndOthers);

        // 顶部区域整体
        QHBoxLayout *pHLayoutTopRegion = NEW_AS_QT(QHBoxLayout);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pHLayoutTopRegion != nullptr, L"pHLayoutTopRegion为空", L"GMEP", L"2024-01-30");
        pHLayoutTopRegion->setContentsMargins(0, 0, 0, 0);
        pHLayoutTopRegion->setSpacing(0);
        pHLayoutTopRegion->addWidget(pFrameTopLeftRegion);
        pHLayoutTopRegion->addWidget(pFrameParametersAndOthers);

        // 全部区域整体
        QVBoxLayout *pVLayoutWhole = NEW_AS_QT(QVBoxLayout);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pVLayoutWhole != nullptr, L"pVLayoutWhole为空", L"GMEP", L"2024-01-30");
        pVLayoutWhole->setContentsMargins(1, 1, 1, 1);
        pVLayoutWhole->setSpacing(0);
        pVLayoutWhole->addLayout(pHLayoutTopRegion);
        if(pLayoutOperationButtons)
            pVLayoutWhole->addLayout(pLayoutOperationButtons);

        setLayout(pVLayoutWhole);
     }

     QLayout *ProjectComponentEditingPage::InitBottomButtonsRegion()
     {
         QCursor pointingHandCursor = QCursor(Qt::CursorShape::PointingHandCursor);

         pBtnCancel = NEW_AS_QT(QPushButton,QString::fromStdWString(GBMP_TR(L"取消")));
         DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pBtnCancel != nullptr, L"pBtnCancel为空", L"GMEP", L"2024-01-30");
         pBtnCancel->setFixedWidth(72);
         pBtnCancel->setFixedHeight(32);
         pBtnCancel->setCursor(pointingHandCursor);
         pBtnCancel->setObjectName("CancelButton");
         pBtnCancel->setStyleSheet(
             "QPushButton#CancelButton{"
             "background-color:rgba(255, 255, 255, 255);"
             "border:1px solid rgba(82, 145, 221, 255);"
             "border-radius:2px;"
             "color:rgba(82, 145, 221, 255);"
             "font-family:\"Microsoft YaHei\";"
             "font-size:14px;"
             "}"
         );
         connect(pBtnCancel, &QPushButton::clicked, [=]() {
             if (!m_context)
             {
                 return;
             }

             if (pBtnSave && !pBtnSave->isEnabled())
             {
                 emit EditingFinished(m_context->GetProjectId(), m_context->GetComponentId(), m_context->GetComponentVersion(),m_isByCommandShow);
                 return;
             }
             std::wstring strInfo = GBMP_TR(L"您的编辑尚未保存，确认退出吗？");
             gnuf::MsgBoardParams msgboardParams;
             msgboardParams.cbSize = { -1, -1 };
             msgboardParams.owner = 0;
             msgboardParams.text = strInfo;
             msgboardParams.caption = GBMP_TR(L"提示");
             msgboardParams.iconDir = L":/images/Announcement/Info";
             msgboardParams.withCloseButton = false;
             msgboardParams.defaultBtn = 2;
             msgboardParams.buttons[0] = GBMP_TR(L"退出");
             msgboardParams.buttons[1] = GBMP_TR(L"继续编辑");
             int retValue = gnuf::ShowMessageBoardIndirect(msgboardParams);


             if (retValue == 0)
             {
                 emit EditingFinished(m_context->GetProjectId(), m_context->GetComponentId(), m_context->GetComponentVersion(), m_isByCommandShow);
                 return;
             }
         });

         pBtnUpdatePreview = NEW_AS_QT(QPushButton, QString::fromStdWString(GBMP_TR(L"更新预览"))); 
         DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pBtnUpdatePreview != nullptr, L"pBtnUpdatePreview为空", L"GMEP", L"2024-01-30");
         pBtnUpdatePreview->setFixedWidth(72);
         pBtnUpdatePreview->setFixedHeight(32);
         pBtnUpdatePreview->setCursor(pointingHandCursor);
         pBtnUpdatePreview->setObjectName("UpdatePreviewButton");
         pBtnUpdatePreview->setStyleSheet(
             "QPushButton#UpdatePreviewButton{"
             "background-color:rgba(82, 145, 221,255);"
             "border:none;"
             "border-radius:2px;"
             "color:rgba(255, 255, 255, 255);"
             "font-family:\"Microsoft YaHei\";"
             "font-size:14px;"
             "}QPushButton#UpdatePreviewButton:disabled{"
             "background-color:rgba(176, 178, 185, 255);"
             "color:rgba(120, 122, 131, 255);"
             "}"
         );
         pBtnUpdatePreview->setDisabled(true);
         connect(pBtnUpdatePreview, &QPushButton::clicked, [=]() {
             if (!m_context)
             {
                 return;
             }

             auto currentSpec = m_context->GetCurrentSpecificationName();
             m_context->Stage(currentSpec);
         });

         pBtnSave = NEW_AS_QT(QPushButton,QString::fromStdWString(GBMP_TR(L"保存")));
         DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pBtnSave != nullptr, L"pBtnSave为空", L"GMEP", L"2024-01-30");
         pBtnSave->setFixedWidth(72);
         pBtnSave->setFixedHeight(32);
         pBtnSave->setCursor(pointingHandCursor);
         pBtnSave->setObjectName("SaveButton");
         pBtnSave->setStyleSheet(
             "QPushButton#SaveButton{"
             "background-color:rgba(82, 145, 221,255);"
             "border:none;"
             "border-radius:2px;"
             "color:rgba(255, 255, 255, 255);"
             "font-family:\"Microsoft YaHei\";"
             "font-size:14px;"
             "}QPushButton#SaveButton:disabled{"
             "background-color:rgba(176, 178, 185, 255);"
             "color:rgba(120, 122, 131, 255);"
             "}"
         );
         pBtnSave->setEnabled(false);

         PermissionWatcher::Get()->OnCurrentPermissionChanged([=](const int oldPermission, const int newPermission) {
             if (newPermission == Permission::SOFTWRITE)
             {
                 pBtnSave->setEnabled(false);
                 pBtnSave->setToolTip(QString::fromStdWString(GBMP_TR(L"示例项目中无该功能权限")));
             }
             else
             {
                 pBtnSave->setToolTip(QString());
                 if (!m_context)
                 {
                     pBtnSave->setEnabled(false);
                 }
                 else
                 {
                     auto state = m_context->GetModifyState();
                     pBtnSave->setEnabled(
                          ((state & EditingProjectComponentContext::ModifyState::Changed) != 0) ||
                         ((state & EditingProjectComponentContext::ModifyState::Dirty) != 0));
                 }
             }
         });
         connect(pBtnSave, &QPushButton::clicked, [=]() {
             if (!m_context)
             {
                 return;
             }
             gmep::GmepRecordTimeUtils::RecordFunctionalServicesStartTime(GMEP_EDIT_PROJECT_COMPONENT);
             auto canUpdateAfterSave = false;
             auto currentProjectId = IProjectManager::Get()->GetCurrentProjectId();
             if (currentProjectId != m_context->GetProjectId())
             {
                 canUpdateAfterSave = false;
             }

             if (AppService::IsGmep())
             {
                 canUpdateAfterSave = true;
             }
             else
             {
                 canUpdateAfterSave = ProjectLoadedComponentService::Get()->IsComponentUpdatable(m_context->GetComponentId(), m_context->GetComponentVersion() + 1);
             }

             bool shouldUpdateAfterSave = false;
             //这里可以不用提示了
             auto dialogResult = SavingEditingProjectComponentDialog::Show(canUpdateAfterSave, shouldUpdateAfterSave,m_isPrivateEnv, this);
             if (dialogResult != SavingEditingProjectComponentDialog::MessageDialogResult::ResultOk)
             {
                 return;
             }
              // 若不马上上传，则保存到本地
             {
                 int nNumUpdateInDocument = 0;
                 bool hasChangeAfterSync = false;
                 std::wstring strSyncSuccInfo = L"";
                 if (m_context->Save(shouldUpdateAfterSave, nNumUpdateInDocument, hasChangeAfterSync, strSyncSuccInfo))
                 {
                     std::wstring strPrompt = GBMP_TR(L"保存成功。");
                     // 若有重新加载族，需要给予提示
                     if (nNumUpdateInDocument > 0)
                         strPrompt += GBMP_TR(L"构件已更新至此工作单元。");
                     // 若用户check了同步至项目构件库，则给予修改成功或后台正在解析等提示。
                     if (hasChangeAfterSync && !strSyncSuccInfo.empty())
                         strPrompt += strSyncSuccInfo;
                     
                     gcmp::NotificationUtils::PostNotification(gcmp::NotificationTypes::SuccessNotificationType, strPrompt);
                                          
                     emit EditingFinished(m_context->GetProjectId(), m_context->GetComponentId(), m_context->GetComponentVersion() + 1, m_isByCommandShow);
                 }
             }

             gmep::GmepRecordTimeUtils::RecordFunctionalServicesEndTimeAndGetDuration(GBMP_TR(L"编辑完成"), GBMP_TR(L"构件相关"), GMEP_EDIT_PROJECT_COMPONENT);
         });

         QHBoxLayout *pHLayoutOperationButtons = NEW_AS_QT(QHBoxLayout);
         DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pHLayoutOperationButtons != nullptr, L"pHLayoutOperationButtons为空", L"GMEP", L"2024-01-30");
         pHLayoutOperationButtons->setContentsMargins(16, 16, 16, 16);
         pHLayoutOperationButtons->setSpacing(16);
         pHLayoutOperationButtons->addStretch();
         pHLayoutOperationButtons->addWidget(pBtnCancel);
         pHLayoutOperationButtons->addWidget(pBtnUpdatePreview);
         pHLayoutOperationButtons->addWidget(pBtnSave);

         QFrame *pFrameOperationButtons = NEW_AS_QT(QFrame);
         DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pFrameOperationButtons != nullptr, L"pFrameOperationButtons为空", L"GMEP", L"2024-01-30");
         pFrameOperationButtons->setObjectName("OperationButtonsFrame");
         pFrameOperationButtons->setStyleSheet("QFrame#OperationButtonsFrame{"
             "border-top:1px solid rgba(189, 199, 213, 255);"
             "}"
         );
         pFrameOperationButtons->setLayout(pHLayoutOperationButtons);

         QHBoxLayout *pHlWhole = NEW_AS_QT(QHBoxLayout);
         DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pHlWhole != nullptr, L"pHlWhole为空", L"GMEP", L"2024-01-30");
         pHlWhole->setContentsMargins(0, 0, 0, 0);
         pHlWhole->setSpacing(0);
         pHlWhole->addWidget(pFrameOperationButtons);

         return pHlWhole;
     }

     QWidget *ProjectComponentEditingPage::InitLegendCardsRegion()
     {
         QSize legendCardSize(128, 128);

         // 平面图例
         pPlanLegendCard = NEW_AS_QT(LegendEditingCard,QString::fromStdWString(GBMP_TR(L"平面图例")));
         DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pPlanLegendCard != nullptr, L"pPlanLegendCard为空", L"GMEP", L"2024-01-30");
         pPlanLegendCard->setObjectName("PlanLegendCard");
         pPlanLegendCard->setFixedSize(legendCardSize);
        
         // 替换
         connect(pPlanLegendCard, &LegendEditingCard::ChangingLegendRequired, [=](std::shared_ptr<ILegend> current) {
             if (!m_context)
             {
                 return;
             }

             std::shared_ptr<ILegend> chosenPlanLegend = current;
             auto result = LegendChoosingDialog::Show(
                 m_context->GetProjectId(),
                 m_context->GetEnterpriseId(),
                 m_context->GetActiveCategoryCode(),
                 m_context->GetActiveCategoryGuid(),
                 m_isPrivateEnv,
                 ILegend::LegendType::Plan, chosenPlanLegend, this);
             if (result != LegendChoosingDialog::MessageDialogResult::ResultOk || chosenPlanLegend == nullptr)
             {
                 return;
             }
             
             auto modified = m_context->ModifyLegend(ILegend::LegendType::Plan, current, chosenPlanLegend);
             if (modified)
             {
                 std::shared_ptr<ILegend> spPlanLegend = m_context->GetActiveLegend(ILegend::LegendType::Plan);
                 pPlanLegendCard->SetLegend(spPlanLegend);
             }
         });

         // 删除
         connect(pPlanLegendCard, &LegendEditingCard::RemovingLegendRequired, [=](std::shared_ptr<ILegend> current) {
             if (!m_context)
             {
                 return;
             }

             if (current == nullptr)
             {
                 return;
             }

             gnuf::MsgBoardReturnValue result = gnuf::ShowMessageBoard(GBMP_TR(L"确认删除当前平面图例？"), GBMP_TR(L"提示"), gnuf::eMB_OKCANCEL | gnuf::eMB_ICONINFORMATION);
             if (result != gnuf::MsgBoardReturnValue::eIDOK)
             {
                 return;
             }

             auto removed = m_context->ModifyLegend(ILegend::LegendType::Plan, current, nullptr);
             if (removed)
             {
                 std::shared_ptr<ILegend> spPlanLegend = m_context->GetActiveLegend(ILegend::LegendType::Plan);
                 pPlanLegendCard->SetLegend(spPlanLegend);
             }
         });

         // 立面图例
         pElevationLegendCard = NEW_AS_QT( LegendEditingCard,QString::fromStdWString(GBMP_TR(L"立面图例")));
         DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pElevationLegendCard != nullptr, L"pElevationLegendCard为空", L"GMEP", L"2024-01-30");
         pElevationLegendCard->setObjectName("ElevationLegendCard");
         pElevationLegendCard->setFixedSize(legendCardSize);

         // 替换
         connect(pElevationLegendCard, &LegendEditingCard::ChangingLegendRequired, [=](std::shared_ptr<ILegend> current) {
             if (!m_context)
             {
                 return;
             }
             
             std::shared_ptr<ILegend> choseElevationnLegend = current;
             auto result = LegendChoosingDialog::Show(
                 m_context->GetProjectId(),
                 m_context->GetEnterpriseId(),
                 m_context->GetActiveCategoryCode(),
                 m_context->GetActiveCategoryGuid(),
                 m_isPrivateEnv,
                 ILegend::LegendType::Elevation, choseElevationnLegend, this);
             if (result != LegendChoosingDialog::MessageDialogResult::ResultOk || choseElevationnLegend == nullptr)
             {
                 return;
             }

             auto modified = m_context->ModifyLegend(ILegend::LegendType::Elevation, current, choseElevationnLegend);
             if (modified)
             {
                 std::shared_ptr<ILegend> spElevationLegend = m_context->GetActiveLegend(ILegend::LegendType::Elevation);
                 pElevationLegendCard->SetLegend(spElevationLegend);
             }
         });

         // 删除
         connect(pElevationLegendCard, &LegendEditingCard::RemovingLegendRequired, [=](std::shared_ptr<ILegend> current) {
             if (!m_context)
             {
                 return;
             }

             if (current == nullptr)
             {
                 return;
             }

             gnuf::MsgBoardReturnValue result = gnuf::ShowMessageBoard(GBMP_TR(L"确认删除当前立面图例？"), GBMP_TR(L"提示"), gnuf::eMB_OKCANCEL | gnuf::eMB_ICONINFORMATION);
             if (result != gnuf::MsgBoardReturnValue::eIDOK)
             {
                 return;
             }

             auto removed = m_context->ModifyLegend(ILegend::LegendType::Elevation, current, nullptr);
             if (removed)
             {
                 std::shared_ptr<ILegend> spElevationLegend = m_context->GetActiveLegend(ILegend::LegendType::Elevation);
                 pElevationLegendCard->SetLegend(spElevationLegend);
             }
         });

         // 侧面图例
         pProfileLegendCard = NEW_AS_QT( LegendEditingCard,QString::fromStdWString(GBMP_TR(L"侧面图例")));
         DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pProfileLegendCard != nullptr, L"pProfileLegendCard为空", L"GMEP", L"2024-01-30");
         pProfileLegendCard->setObjectName("ProfileLegendCard");
         pProfileLegendCard->setFixedSize(legendCardSize);

         // 替换
         connect(pProfileLegendCard, &LegendEditingCard::ChangingLegendRequired, [=](std::shared_ptr<ILegend> current) {
             if (!m_context)
             {
                 return;
             }

             std::shared_ptr<ILegend> choseProfileLegend = current;
             auto result = LegendChoosingDialog::Show(
                 m_context->GetProjectId(),
                 m_context->GetEnterpriseId(),
                 m_context->GetActiveCategoryCode(), 
                 m_context->GetActiveCategoryGuid(), 
                 m_isPrivateEnv,
                 ILegend::LegendType::Profile, choseProfileLegend, this);
             if (result != LegendChoosingDialog::MessageDialogResult::ResultOk || choseProfileLegend == nullptr)
             {
                 return;
             }

             auto modified = m_context->ModifyLegend(ILegend::LegendType::Profile, current, choseProfileLegend);
             if (modified)
             {
                 std::shared_ptr<ILegend> spProfileLegend = m_context->GetActiveLegend(ILegend::LegendType::Profile);
                 pProfileLegendCard->SetLegend(spProfileLegend);
             }
         });

         // 删除
         connect(pProfileLegendCard, &LegendEditingCard::RemovingLegendRequired, [=](std::shared_ptr<ILegend> current) {
             if (!m_context)
             {
                 return;
             }

             if (current == nullptr)
             {
                 return;
             }

             gnuf::MsgBoardReturnValue result = gnuf::ShowMessageBoard(GBMP_TR(L"确认删除当前侧面图例？"), GBMP_TR(L"提示"), gnuf::eMB_OKCANCEL | gnuf::eMB_ICONINFORMATION);
             if (result != gnuf::MsgBoardReturnValue::eIDOK)
             {
                 return;
             }

             auto removed = m_context->ModifyLegend(ILegend::LegendType::Profile, current, nullptr);
             if (removed)
             {
                 std::shared_ptr<ILegend> spProflieLegend = m_context->GetActiveLegend(ILegend::LegendType::Profile);
                 pProfileLegendCard->SetLegend(spProflieLegend);
             }
         });

         // 电气图例
         pElectricLegendCard = NEW_AS_QT(LegendEditingCard, QString::fromStdWString(GBMP_TR(L"电气图例")));
         DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pElectricLegendCard != nullptr, L"pElectricLegendCard为空", L"GMEP", L"2024-01-30");
         pElectricLegendCard->setObjectName("ElectricLegendCard");
         pElectricLegendCard->setFixedSize(legendCardSize);

         // 替换
         connect(pElectricLegendCard, &LegendEditingCard::ChangingLegendRequired, [=](std::shared_ptr<ILegend> current) {
             if (!m_context)
             {
                 return;
             }

             std::shared_ptr<ILegend> chosenElectricLegend = current;
             auto result = LegendChoosingDialog::Show(
                 m_context->GetProjectId(),
                 m_context->GetEnterpriseId(),
                 m_context->GetActiveCategoryCode(), 
                 m_context->GetActiveCategoryGuid(), 
                 m_isPrivateEnv,
                 ILegend::LegendType::Electric, chosenElectricLegend, this);
             if (result != LegendChoosingDialog::MessageDialogResult::ResultOk || chosenElectricLegend == nullptr)
             {
                 return;
             }

             auto modified = m_context->ModifyLegend(ILegend::LegendType::Electric, current, chosenElectricLegend);
             if (modified)
             {
                 std::shared_ptr<ILegend> spElectricLegend = m_context->GetActiveLegend(ILegend::LegendType::Electric);
                 pElectricLegendCard->SetLegend(spElectricLegend);
             }
         });

         // 删除
         connect(pElectricLegendCard, &LegendEditingCard::RemovingLegendRequired, [=](std::shared_ptr<ILegend> current) {
             if (!m_context)
             {
                 return;
             }

             if (current == nullptr)
             {
                 return;
             }

             gnuf::MsgBoardReturnValue result = gnuf::ShowMessageBoard(GBMP_TR(L"确认删除当前电气图例？"), GBMP_TR(L"提示"), gnuf::eMB_OKCANCEL | gnuf::eMB_ICONINFORMATION);
             if (result != gnuf::MsgBoardReturnValue::eIDOK)
             {
                 return;
             }

             auto removed = m_context->ModifyLegend(ILegend::LegendType::Electric, current, nullptr);
             if (removed)
             {
                 std::shared_ptr<ILegend> spElectricLegend = m_context->GetActiveLegend(ILegend::LegendType::Electric);
                 pElectricLegendCard->SetLegend(spElectricLegend);
             }
         });

         QHBoxLayout *pHLLegends = NEW_AS_QT(QHBoxLayout);
         DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pHLLegends != nullptr, L"pHLLegends为空", L"GMEP", L"2024-01-30");
         pHLLegends->setContentsMargins(0, 16, 0, 16);
         pHLLegends->setSpacing(16);
         pHLLegends->addWidget(pPlanLegendCard);
         pHLLegends->setAlignment(pPlanLegendCard, Qt::AlignTop | Qt::AlignLeft);
         pHLLegends->addWidget(pElevationLegendCard);
         pHLLegends->setAlignment(pElevationLegendCard, Qt::AlignTop | Qt::AlignLeft);
         pHLLegends->addWidget(pProfileLegendCard);
         pHLLegends->setAlignment(pProfileLegendCard, Qt::AlignTop | Qt::AlignLeft);
         pHLLegends->addWidget(pElectricLegendCard);
         pHLLegends->setAlignment(pElectricLegendCard, Qt::AlignTop | Qt::AlignLeft);
         pHLLegends->addStretch();

         QWidget *pWgtLegends = NEW_AS_QT(QWidget,this);
         DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pWgtLegends != nullptr, L"pWgtLegends为空", L"GMEP", L"2024-01-30");
         pWgtLegends->setLayout(pHLLegends);

         return pWgtLegends;
     }

     QLayout *ProjectComponentEditingPage::InitComponentNameAndCategoryRegion()
     {
         QString captionlabelStyle =
             "QLabel{"
             "font-family:\"Microsoft YaHei\";"
             "font-size:12px;"
             "color:rgba(0, 0, 0, 255);"
             "}";

         // component name caption
         QLabel *pLblComponentNameCaption = NEW_AS_QT( QLabel,QString::fromStdWString(GBMP_TR(L"名称：")));
         DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pLblComponentNameCaption, L"regExp为空", L"GMEP", L"2024-01-30");
         pLblComponentNameCaption->setStyleSheet(captionlabelStyle);
         
         // component name lineEdit
         m_pLeComponentName = NEW_AS_QT(QLineEdit);
         DBG_WARN_AND_RETURN_NULLPTR_UNLESS(m_pLeComponentName, L"regExp为空", L"GMEP", L"2024-01-30");
         m_pLeComponentName->setObjectName("EdittingName");
         m_pLeComponentName->setStyleSheet("QLineEdit{"
             "font-family:\"Microsoft YaHei\";"
             "font-size:12px;"
             "color:rgba(0, 0, 0, 255);"
             "}"
         );

         // 非法字符 <>/\\\":?*| 不可以保存
         QRegExpValidator* regExp = NEW_AS_QT(QRegExpValidator, QRegExp(tr("^[^<>/\\\":?*|]+$")));
         DBG_WARN_AND_RETURN_NULLPTR_UNLESS(regExp, L"regExp为空", L"GMEP", L"2024-01-30");
         UserValidatorData* data = NEW_AS_QT(UserValidatorData);
         DBG_WARN_AND_RETURN_NULLPTR_UNLESS(data, L"data为空", L"GMEP", L"2024-01-30");
         data->validate = regExp;

         m_pLeComponentName->setUserData(Qt::UserRole, data);
         QObjectList list;
         list.push_back(m_pLeComponentName);

         QtFormValueValidator & lineEditValidator = QtFormValueValidator::GetInstance();
         lineEditValidator.RegularValidatorCheck(list);

         connect(m_pLeComponentName, &QLineEdit::textChanged, [=](const QString &text) {
             if (!m_context)
             {
                 return;
             }

             std::wstring componentName = text.trimmed().toStdWString();
             m_context->ModifyComponentName(componentName);
         });

         // category caption
         QLabel *pLblCategoryCaption = NEW_AS_QT( QLabel,QString::fromStdWString(GBMP_TR(L"分类：")));
         pLblCategoryCaption->setAlignment(Qt::AlignVCenter);
         pLblCategoryCaption->setStyleSheet(captionlabelStyle);

         // category label
         m_pLblCategoryName = NEW_AS_QT(QLabel);
         DBG_WARN_AND_RETURN_NULLPTR_UNLESS(m_pLblCategoryName, L"m_pLblCategoryName为空", L"GMEP", L"2024-01-30");
         m_pLblCategoryName->setAlignment(Qt::AlignVCenter);
         m_pLblCategoryName->setStyleSheet(
             "QLabel{"
             "font-family:\"Microsoft YaHei\";"
             "font-size:12px;"
             "color:rgba(0, 0, 0, 255);"
             "}"
         );

         QHBoxLayout *pLayoutWhole = NEW_AS_QT(QHBoxLayout);
         pLayoutWhole->setContentsMargins(16, 16, 16, 8);
         pLayoutWhole->setSpacing(0);
         pLayoutWhole->addWidget(pLblComponentNameCaption);
         pLayoutWhole->setAlignment(pLblComponentNameCaption, Qt::AlignVCenter);
         pLayoutWhole->addSpacing(0);
         pLayoutWhole->addWidget(m_pLeComponentName, 1);
         pLayoutWhole->setAlignment(m_pLeComponentName, Qt::AlignVCenter);
         pLayoutWhole->addSpacing(34);
         pLayoutWhole->addWidget(pLblCategoryCaption);
         pLayoutWhole->setAlignment(pLblCategoryCaption, Qt::AlignVCenter);
         pLayoutWhole->addSpacing(0);
         pLayoutWhole->addWidget(m_pLblCategoryName, 1);
         pLayoutWhole->setAlignment(m_pLblCategoryName, Qt::AlignVCenter);

         return pLayoutWhole;
     }

     QLayout * ProjectComponentEditingPage::InitSpecificationsRegion()
     {
         QLabel *pLblSpec = NEW_AS_QT( QLabel,QString::fromStdWString(GBMP_TR(L"类型")));
         pLblSpec->setStyleSheet("QLabel{"
             "font-family:\"Microsoft YaHei\";"
             "font-size:14px;"
             "color:rgba(102, 102, 102, 255);"
             "}"
         );

         m_pCbbSpec = NEW_AS_QT(QComboBox);
         DBG_WARN_AND_RETURN_NULLPTR_UNLESS(m_pCbbSpec, L"m_pCbbSpec为空", L"GMEP", L"2024-01-30");
         m_pCbbSpec->setObjectName("SpecificationComboBox");
         m_pCbbSpec->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
         m_pCbbSpec->setStyleSheet("QComboBox{"
             "font-family:\"Microsoft YaHei\";"
             "font-size:12px;"
             "color:rgba(40, 40, 51, 255);"
             "}"
         );
         connect(m_pCbbSpec, static_cast<void (QComboBox:: *)(const QString &)>(&QComboBox::currentIndexChanged), [=](const QString &spec) {
             if (!m_context)
             {
                 return;
             }
             if (!m_bSwitchCurrentSpecificationTo)
             {
                 return;
             }

             m_context->SwitchCurrentSpecificationTo(spec.toStdWString());
         });

         QString btnStyle = "QPushButton{"
             "background:transparent;"
             "border:1px solid rgba(189, 199, 213, 255);"
             "border-radius:2px;"
             "}";
         QCursor btnCursor(Qt::CursorShape::PointingHandCursor);

         m_pBtnCreateNewSpec = NEW_AS_QT(QPushButton,QIcon(":/images/icon_plus_sharp_819AAD_16_16.png"), QString());
         DBG_WARN_AND_RETURN_NULLPTR_UNLESS(m_pBtnCreateNewSpec, L"m_pBtnCreateNewSpec为空", L"GMEP", L"2024-01-30");
         m_pBtnCreateNewSpec->setObjectName("CreateSpecificationButton");
         m_pBtnCreateNewSpec->setToolTip(QString::fromStdWString(GBMP_TR(L"新建类型")));
         m_pBtnCreateNewSpec->setFixedSize(QSize(24, 24));
         m_pBtnCreateNewSpec->setStyleSheet(btnStyle);
         m_pBtnCreateNewSpec->setCursor(btnCursor);
         connect(m_pBtnCreateNewSpec, &QPushButton::clicked, [=]() {
             if (!m_context)
             {
                 return;
             }
             auto exisitedSpecifcations = m_context->GetActiveSpecifications();
             auto currentSpecfication = m_context->GetCurrentSpecificationName();
             std::wstring addedSpecification;
             auto result = SpecificationAddingDialog::Show(exisitedSpecifcations, currentSpecfication, addedSpecification, this);
             if (result != SpecificationAddingDialog::MessageDialogResult::ResultOk)
             {
                 return;
             }
             auto finalAddedSpecificationName = QString::fromStdWString(addedSpecification).trimmed().toStdWString();
             if (finalAddedSpecificationName.empty() || currentSpecfication == finalAddedSpecificationName)
             {
                 return;
             }

             m_context->CopySpecification(currentSpecfication, finalAddedSpecificationName);
         });

         m_pBtnRenameSpec = NEW_AS_QT (QPushButton,QIcon(":/images/icon_rename_819AAD_16_16.png"), QString());
         DBG_WARN_AND_RETURN_NULLPTR_UNLESS(m_pBtnRenameSpec, L"m_pBtnRenameSpec为空", L"GMEP", L"2024-01-30");
         m_pBtnRenameSpec->setObjectName("RenameSpecificationButton");
         m_pBtnRenameSpec->setToolTip(QString::fromStdWString(GBMP_TR(L"重命名类型")));
         m_pBtnRenameSpec->setFixedSize(QSize(24, 24));
         m_pBtnRenameSpec->setStyleSheet(btnStyle);
         m_pBtnRenameSpec->setCursor(btnCursor);
         connect(m_pBtnRenameSpec, &QPushButton::clicked, [=]() {
             if (!m_context)
             {
                 return;
             }

             auto exisitedSpecifcations = m_context->GetActiveSpecifications();
             auto specficationOldName = m_context->GetCurrentSpecificationName();
             std::wstring specificationNewName;
             auto result = SpecificationRenamingDialog::Show(exisitedSpecifcations, specficationOldName, specificationNewName, this);

             if ((result == SpecificationRenamingDialog::MessageDialogResult::ResultOk) &&
                 (specficationOldName != specificationNewName))
             {
                 m_context->RenameSpecification(specficationOldName, specificationNewName);
             }
         });

         m_pBtnDeleteSpec = NEW_AS_QT( QPushButton,QIcon(":/images/icon_delete_bin_819AAD_16_16.png"), QString());
         DBG_WARN_AND_RETURN_NULLPTR_UNLESS(m_pBtnDeleteSpec, L"m_pBtnDeleteSpec为空", L"GMEP", L"2024-01-30");
         m_pBtnDeleteSpec->setObjectName("DeleteSpecificationButton");
         m_pBtnDeleteSpec->setToolTip(QString::fromStdWString(GBMP_TR(L"删除类型")));
         m_pBtnDeleteSpec->setFixedSize(QSize(24, 24));
         m_pBtnDeleteSpec->setStyleSheet(btnStyle);
         m_pBtnDeleteSpec->setCursor(btnCursor);
         connect(m_pBtnDeleteSpec, &QPushButton::clicked, [=]() {
             if (!m_context)
             {
                 return;
             }

             auto currentSpec = m_context->GetCurrentSpecificationName();
             
             std::wstring strInfo = gcmp::StringUtil::FormatWString(GBMP_TR(L"确认删除类型 %s?"), currentSpec.c_str());
             gnuf::MsgBoardReturnValue retValue = gnuf::ShowMessageBoard(strInfo,
                 GBMP_TR(L"提示"), gnuf::eMB_OKCANCEL | gnuf::eMB_ICONINFORMATION);
             if (retValue == gnuf::MsgBoardReturnValue::eIDOK)
             {
                 m_context->RemoveSpecification(currentSpec);
             }
         });

         QHBoxLayout *pHLayoutSpec = NEW_AS_QT(QHBoxLayout);
         pHLayoutSpec->setContentsMargins(16, 16, 16, 0);
         pHLayoutSpec->setSpacing(8);
         pHLayoutSpec->addWidget(pLblSpec);
         pHLayoutSpec->addWidget(m_pCbbSpec);
         pHLayoutSpec->addWidget(m_pBtnCreateNewSpec);
         pHLayoutSpec->addWidget(m_pBtnRenameSpec);
         pHLayoutSpec->addWidget(m_pBtnDeleteSpec);

         return pHLayoutSpec;
     }

     QWidget * ProjectComponentEditingPage::InitGeometryParametersRegion()
     {
         m_pGeoParametersTable = NEW_AS_QT(EdittingParametersTableView);
         DBG_WARN_AND_RETURN_NULLPTR_UNLESS(m_pGeoParametersTable != nullptr, L"m_pGeoParametersTable为空", L"GMEP", L"2024-01-30");
         m_pGeoParametersTable->setObjectName("GeoParameterTable");
         m_pGeoParametersTable->setSizePolicy(QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Fixed);
         m_pGeoParametersTable->SetSizeToContent(true);         
         
         auto model = dynamic_cast<EdittingParametersTableModel *>(m_pGeoParametersTable->model());
         DBG_WARN_UNLESS(model, L"model为空", L"GMEP", L"2024-01-30");

         // 修改参数值
         connect(model, &EdittingParametersTableModel::ModifyValueOfParameterRequired,
             [=](const std::wstring &parameterName, const std::wstring &parameterOldValue, const std::wstring &parameterNewValue) {
             if (!m_context)
             {
                 return;
             }
             auto currentSpec = m_context->GetCurrentSpecificationName();
             auto result = m_context->ModifyParameterValue(currentSpec, parameterName, parameterOldValue, parameterNewValue);
             if (result)
             {
                 model->UpdateParameterValue(parameterName, parameterOldValue, parameterNewValue);
             }
         });

         QHBoxLayout *pHLayoutGeoParametersTable = NEW_AS_QT(QHBoxLayout);
         DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pHLayoutGeoParametersTable != nullptr, L"pHLayoutGeoParametersTable为空", L"GMEP", L"2024-01-30");
         pHLayoutGeoParametersTable->setContentsMargins(16, 16, 16, 16);
         pHLayoutGeoParametersTable->setSpacing(0);
         pHLayoutGeoParametersTable->addWidget(m_pGeoParametersTable);
         pHLayoutGeoParametersTable->setAlignment(m_pGeoParametersTable, Qt::AlignTop);
         pHLayoutGeoParametersTable->setSizeConstraint(QLayout::SizeConstraint::SetMinimumSize);

         QWidget *pGeoParametersScrollWidget = NEW_AS_QT(QWidget);
         DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pGeoParametersScrollWidget != nullptr, L"pGeoParametersScrollWidget为空", L"GMEP", L"2024-01-30");
         pGeoParametersScrollWidget->setObjectName("GeoParametersScrollWidget");
         pGeoParametersScrollWidget->setStyleSheet("QWidget#GeoParametersScrollWidget{background:rgba(245, 245, 245, 255);}");
         pGeoParametersScrollWidget->setLayout(pHLayoutGeoParametersTable);
         connect(m_pGeoParametersTable, &EdittingParametersTableView::SizedToContent, [=]() {
             pGeoParametersScrollWidget->setFixedHeight(
                 m_pGeoParametersTable->height() +
                 pHLayoutGeoParametersTable->contentsMargins().top() +
                 pHLayoutGeoParametersTable->contentsMargins().bottom()
             );
         });

         pGeoParametersScroller = NEW_AS_QT(CustomScroller);
         DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pGeoParametersScroller != nullptr, L"pGeoParametersScroller为空", L"GMEP", L"2024-01-30");
         pGeoParametersScroller->setObjectName("GeoParameterScroller");
         pGeoParametersScroller->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
         pGeoParametersScroller->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded);
         pGeoParametersScroller->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff);
         pGeoParametersScroller->setStyleSheet("QScrollArea{"
             "border:none;"
             "background:rgba(245, 245, 245, 255);"
             "}"
         );
         pGeoParametersScroller->setWidget(pGeoParametersScrollWidget);
         pGeoParametersScroller->SetStretchHorizontal(true);

         return pGeoParametersScroller;
     }

     QWidget * ProjectComponentEditingPage::InitProductParametersRegion()
     {
         // drawer chest
         DrawerChest *pDrawerChest = NEW_AS_QT(DrawerChest);
         DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDrawerChest != nullptr, L"pDrawerChest为空", L"GMEP", L"2024-01-30");
         pDrawerChest->setObjectName("DrawerChestWidget");
         pDrawerChest->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);

         // standard parameters card
         InitStandardParametersCard();
         pDrawerChest->AddDrawer(pStandardParametersCard);

         // custom parameters card
         //InitCustomParametersCard();
       //  pDrawerChest->AddDrawer(pCustomParametersCard);
                          
         // scroller
         pProdParametersScroller = NEW_AS_QT(CustomScroller);
         DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pProdParametersScroller != nullptr, L"pProdParametersScroller为空", L"GMEP", L"2024-01-30");
         pProdParametersScroller->setObjectName("ProdParametersScroller");
         pProdParametersScroller->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
         pProdParametersScroller->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded);
         pProdParametersScroller->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff);
         pProdParametersScroller->setStyleSheet("QScrollArea{"
             "border:none;"
             "background:rgba(245, 245, 245, 255);"
             "}"
         );
         pProdParametersScroller->setWidget(pDrawerChest);
         pProdParametersScroller->SetStretchHorizontal(true);
         connect(pStandardParametersCard, &ParametersEditingCard::ParametersChanged, [=]() {
             pProdParametersScroller->ensureVisible(0, 0);
         });

         return pProdParametersScroller;
     }

     void ProjectComponentEditingPage::InitStandardParametersCard()
     {
         pStandardParametersCard = NEW_AS_QT(ParametersEditingCard,QString::fromStdWString(GBMP_TR(L"标准属性")), QString::fromStdWString(GBMP_TR(L"（已根据分类自动匹配标准产品属性）")));
         DBG_WARN_AND_RETURN_VOID_UNLESS(pStandardParametersCard != nullptr, L"pStandardParametersCard为空", L"GMEP", L"2024-01-30");
         pStandardParametersCard->setObjectName("StandardParametersCard");
         
         // 添加参数
         connect(pStandardParametersCard, &ParametersEditingCard::AddingParamtersRequired, [=]() {
             if (!m_context)
             {
                 return;
             }

             std::shared_ptr<ICategoryProperty> categoryProperty = m_context->GetActiveCategoryProperty();
             std::map<std::wstring, std::shared_ptr<IParameterDefinition>> existedParameterDefinitions = m_context->GetActiveParameterDefinitions();
             std::map<std::wstring, std::shared_ptr<IParameterDefinition>> finalAddedParameterDefinitions;
             std::map<std::wstring, std::shared_ptr<IParameterDefinition>> finalRemovedParameterDefinitions;
             auto result = StandardParametersChoosingDialog::Show(categoryProperty, existedParameterDefinitions, finalAddedParameterDefinitions, finalRemovedParameterDefinitions, this);
             
             if (result != StandardParametersChoosingDialog::MessageDialogResult::ResultOk)
             {
                 return;
             }

             if (finalAddedParameterDefinitions.empty() && finalRemovedParameterDefinitions.empty())
             {
                 return;
             }
             
             m_context->ModifyParameterUnit(m_context->GetActiveCategoryCode(), finalAddedParameterDefinitions);
             
             bool removed = false;
             if (!finalRemovedParameterDefinitions.empty())
             {
                 removed = m_context->RemoveParameterDefinitions(finalRemovedParameterDefinitions);
             }

             bool added = false;
             if (!finalAddedParameterDefinitions.empty())
             {
                 added = m_context->AddParameterDefinitions(finalAddedParameterDefinitions);
             }

             if (removed || added)
             {
                 auto currentSpec = m_context->GetCurrentSpecificationName();
                 pStandardParametersCard->SetParameters(m_context->GetActiveStandardParameters(currentSpec));
             }
         });

         // 删除参数
         connect(pStandardParametersCard, &ParametersEditingCard::RemoveParameterRequired,
             [=](const std::wstring &parameterName) {
             if (!m_context)
             {
                 return;
             }

             if (parameterName.empty())
             {
                 return;
             }

               std::wstring strInfo = gcmp::StringUtil::FormatWString(GBMP_TR(L"确认删除参数 %s?"), parameterName.c_str());
             gnuf::MsgBoardReturnValue result = gnuf::ShowMessageBoard(strInfo, GBMP_TR(L"提示"), gnuf::eMB_OKCANCEL | gnuf::eMB_ICONINFORMATION);
             if (result == gnuf::MsgBoardReturnValue::eIDOK)
             {
                 auto map = std::map<std::wstring, std::shared_ptr<IParameterDefinition>>();
                 map[parameterName] = nullptr;

                 auto removed = m_context->RemoveParameterDefinitions(map);
                 if (removed)
                 {
                     auto currentSpec = m_context->GetCurrentSpecificationName();
                     pStandardParametersCard->SetParameters(m_context->GetActiveStandardParameters(currentSpec));
                 }
             }
         });

         // 修改参数值
         connect(pStandardParametersCard, &ParametersEditingCard::ModifyValueOfParameterRequired,
             [=](const std::wstring &parameterName, const std::wstring &parameterOldValue, const std::wstring &parameterNewValue) {
             if (!m_context)
             {
                 return;
             }
             auto currentSpec = m_context->GetCurrentSpecificationName();
             auto result = m_context->ModifyParameterValue(currentSpec, parameterName, parameterOldValue, parameterNewValue);
             if (result)
             {
                 pStandardParametersCard->UpdateParameterValue(parameterName, parameterOldValue, parameterNewValue);
             }
         });

         // 选中状态控制
         connect(pStandardParametersCard, &ParametersEditingCard::SelectionChanged, 
             [=](const QItemSelection &selected, const QItemSelection &deselected) {
             if (!selected.empty())
             {
                 //pCustomParametersCard->ClearSelection();
             }
         });
     }

     void ProjectComponentEditingPage::Resume()
     {
         DBG_WARN_AND_RETURN_VOID_UNLESS(pBtnUpdatePreview, L"pBtnUpdatePreview为空", L"GMEP", L"2024-01-30");
         pBtnUpdatePreview->setEnabled(false);
         DBG_WARN_AND_RETURN_VOID_UNLESS(pBtnSave, L"pBtnSave为空", L"GMEP", L"2024-01-30");
         pBtnSave->setEnabled(false);    

         DBG_WARN_AND_RETURN_VOID_UNLESS(pProdParametersScroller, L"pProdParametersScroller为空", L"GMEP", L"2024-01-30");
         pProdParametersScroller->ensureVisible(0, 0);
         DBG_WARN_AND_RETURN_VOID_UNLESS(pGeoParametersScroller, L"pGeoParametersScroller为空", L"GMEP", L"2024-01-30");
         pGeoParametersScroller->ensureVisible(0, 0);
     }

     void ProjectComponentEditingPage::Prepare(const std::wstring & projectId, const std::wstring & enterpriseId, const std::wstring & componentId, const int32_t & componentVersion, const std::wstring & componentName)
     {
         m_context = std::make_shared<EditingProjectComponentContext>(projectId, enterpriseId,componentId, componentVersion, componentName, nullptr);
         DBG_WARN_AND_RETURN_VOID_UNLESS(m_context, L"m_context为空", L"GMEP", L"2024-01-30");
         connect(m_context.get(), &EditingProjectComponentContext::PrepareFinished, [=](const bool &isReady, const std::wstring errorMessage) {
             if (isReady)
             {
                 PopulateData();
             }
             else
             {
                 if (!errorMessage.empty())
                 {
                     BnufBulletin::SingleShot(errorMessage, BnufBulletin::BulletinIcon::Error);
                 }
                 if (gmepgcs::MainWindow* pMainWindow = UIService::Get()->GetMainWindow())
                 {
                     pMainWindow->HideMask();
                 }
             }
         });
         DBG_WARN_AND_RETURN_VOID_UNLESS(pBtnUpdatePreview, L"pBtnUpdatePreview为空", L"GMEP", L"2024-01-30");
         DBG_WARN_AND_RETURN_VOID_UNLESS(pBtnSave, L"pBtnSave为空", L"GMEP", L"2024-01-30");
         connect(m_context.get(), &EditingProjectComponentContext::StateChanged,
             [=](int oldState, int newState) {
             pBtnUpdatePreview->setEnabled((newState & EditingProjectComponentContext::ModifyState::Dirty) != 0);

             if (newState & EditingProjectComponentContext::ModifyState::Invalid)
             {
                 pBtnSave->setEnabled(false);
             }
             else
             {
                 if (PermissionWatcher::Get()->GetCurrentPermission() == Permission::SOFTWRITE)
                 {
                     pBtnSave->setEnabled(false);
                 }
                 else
                 {
                     pBtnSave->setEnabled(
                         ((newState & EditingProjectComponentContext::ModifyState::Changed) != 0) ||
                         ((newState & EditingProjectComponentContext::ModifyState::Dirty) != 0));
                 }
             }
         });

         DBG_WARN_AND_RETURN_VOID_UNLESS(m_pCbbSpec, L"m_pCbbSpec为空", L"GMEP", L"2024-01-30");
         DBG_WARN_AND_RETURN_VOID_UNLESS(m_pBtnRenameSpec, L"m_pBtnRenameSpec为空", L"GMEP", L"2024-01-30");
         DBG_WARN_AND_RETURN_VOID_UNLESS(m_pBtnDeleteSpec, L"m_pBtnDeleteSpec为空", L"GMEP", L"2024-01-30");
         connect(m_context.get(), &EditingProjectComponentContext::SpecificationItemsChanged,
             [=](const std::vector<std::wstring> &specs) {
             QStringList specList;
             for (auto &spec : specs)
             {
                 specList << QString::fromStdWString(spec);
             }

             m_bSwitchCurrentSpecificationTo = false;
             m_pCbbSpec->clear();
             m_pCbbSpec->addItems(specList);
             m_bSwitchCurrentSpecificationTo = true;

             m_pBtnRenameSpec->setEnabled(specs.size() >= 1);
             m_pBtnDeleteSpec->setEnabled(specs.size() >= 2);
         });

         DBG_WARN_AND_RETURN_VOID_UNLESS(m_pGeoParametersTable, L"m_pGeoParametersTable为空", L"GMEP", L"2024-01-30");
         DBG_WARN_AND_RETURN_VOID_UNLESS(pStandardParametersCard, L"pStandardParametersCard为空", L"GMEP", L"2024-01-30");
         connect(m_context.get(), &EditingProjectComponentContext::CurrentSpecificationChanged,
             [=](const std::wstring &oldSpec, const std::wstring &newSpec) {
             if (newSpec != oldSpec)
             {
                 m_pCbbSpec->setCurrentText(QString::fromStdWString(newSpec));

                 m_pGeoParametersTable->SetParameters(m_context->GetActiveGeometyParameters(newSpec));
                 pStandardParametersCard->SetParameters(m_context->GetActiveStandardParameters(newSpec));
                // pCustomParametersCard->SetParameters(m_context->GetActiveCustomParameters(newSpec));
             }
         });
         connect(m_context.get(), &EditingProjectComponentContext::SuppressedParametersChanged,
             [=](const std::vector<std::wstring> &newlySuppressed, const std::vector<std::wstring> &newlyDesuppressed) {
             if (newlySuppressed.empty() && newlyDesuppressed.empty())
             {
                 return;
             }

             auto currentSpec = m_context->GetCurrentSpecificationName();
           //  pCustomParametersCard->SetParameters(m_context->GetActiveCustomParameters(currentSpec));
         });
         connect(m_context.get(), &EditingProjectComponentContext::DrivenParameterUpdateFinish,
             [=](const bool &success, const bool &hasUpdated) {
             auto currentSpec = m_context->GetCurrentSpecificationName();
             m_pGeoParametersTable->SetParameters(m_context->GetActiveGeometyParameters(currentSpec));
             pStandardParametersCard->SetParameters(m_context->GetActiveStandardParameters(currentSpec));
           //  pCustomParametersCard->SetParameters(m_context->GetActiveCustomParameters(currentSpec));
         });
         DBG_WARN_AND_RETURN_VOID_UNLESS(m_pGac3DViewer, L"m_pGac3DViewer为空", L"GMEP", L"2024-01-30");
         connect(m_context.get(), &EditingProjectComponentContext::GeometryUpdateFinish,
             [=](const bool &success) {
             auto currentSpec = m_context->GetCurrentSpecificationName();
             auto geometryParameters = m_context->GetActiveGeometyParameters(currentSpec);
             auto geometryParametersStr = std::wstring();
             for (auto &geoParam : geometryParameters)
             {
                 if (geoParam && geoParam->Definition && geoParam->Definition->GetParameterType() == L"Double")
                 {
                     if (!geometryParametersStr.empty())
                     {
                         geometryParametersStr += L";";
                     }

                     geometryParametersStr += geoParam->Definition->GetName() + L"=" + geoParam->Value;
                 }
             }

             m_pGac3DViewer->DisplayAsync(m_context->GetComponentLocalFilePath(), geometryParametersStr);
         });
         connect(m_context.get(), &EditingProjectComponentContext::StageFinished,
             [=](const bool &success) {
             if (!success)
             {
                 BnufBulletin::SingleShot(GBMP_TR(L"处理失败，请检查参数是否正确"), BnufBulletin::BulletinIcon::Error);
             }
         });
         connect(m_context.get(), &EditingProjectComponentContext::SaveFinished,
             [=](const bool &success, const std::wstring &errorMessage, std::shared_ptr<IProjectComponent> savedComponent, const bool &shouldUpdateAfterSave) {
             if (!success)
             {
                 gnuf::ShowMessageBoard(errorMessage, GBMP_TR(L"提示"), gnuf::eMB_OK | gnuf::eMB_ICONWARNING);
                 return;
             }
             DBG_WARN_AND_RETURN_VOID_UNLESS(savedComponent, L"savedComponent为空", L"GMEP", L"2024-01-30");          

             if (!shouldUpdateAfterSave)
             {
                 BnufBulletin::SingleShot(L"保存成功", BnufBulletin::BulletinIcon::Success, 500,  nullptr, [=]() {
                     emit EditingFinished(m_context->GetProjectId(), savedComponent->Id, savedComponent->Version, m_isByCommandShow);
                 });
                 return;
             }

             UpdateAfterSave(savedComponent);
         });
         connect(m_context.get(), &EditingProjectComponentContext::ModifyComponentCategoryFinished,
             [=](const bool &sucess, const std::wstring &errorMessage) {
             if (!sucess)
             {
                 if (!errorMessage.empty())
                 {
                     BnufBulletin::SingleShot(errorMessage, BnufBulletin::BulletinIcon::Error);
                 }

                 return;
             }

             auto spec = m_context->GetCurrentSpecificationName();
             m_pGeoParametersTable->SetParameters(m_context->GetActiveGeometyParameters(spec));
             pStandardParametersCard->SetParameters(m_context->GetActiveStandardParameters(spec));
           //  pCustomParametersCard->SetParameters(m_context->GetActiveCustomParameters(spec));

             m_context->ModifyLegend(ILegend::LegendType::Plan, m_context->GetActiveLegend(ILegend::LegendType::Plan), nullptr);
             m_context->ModifyLegend(ILegend::LegendType::Elevation, m_context->GetActiveLegend(ILegend::LegendType::Elevation), nullptr);
             m_context->ModifyLegend(ILegend::LegendType::Profile, m_context->GetActiveLegend(ILegend::LegendType::Profile), nullptr);
             m_context->ModifyLegend(ILegend::LegendType::Electric, m_context->GetActiveLegend(ILegend::LegendType::Electric), nullptr);
             PopulateLegends();
         });

             m_context->Prepare();
     }

     void ProjectComponentEditingPage::PopulateData()
     {
         emit OnProjectComponentEditingPageRequired();

         PopulateComponentName();
         PopulateCategories();
         PopulateSpecifications();

         if (AppService::Get()->IsGmep())
         {
             PopulateLegends();
         }

         Populate3DView();
     }

    void ProjectComponentEditingPage::PopulateComponentName()
    {
        if (!m_context)
        {
            return;
        }

        QString componentName = m_context->GetActiveComponentName();
        if (m_pLeComponentName)
        {
            m_pLeComponentName->setText(componentName);
        }      
    }

    void ProjectComponentEditingPage::PopulateCategories()
    {
        if (!m_context)
        {
            return;
        }

        DBG_WARN_AND_RETURN_VOID_UNLESS(m_pLblCategoryName, L"m_pLblCategoryName为空", L"GMEP", L"2024-01-30");
        m_pLblCategoryName->setText(QString::fromStdWString(m_context->GetActiveCategoryFullName()));
    }

    void ProjectComponentEditingPage::PopulateSpecifications()
    {
        if (!m_context)
        {
            return;
        }

        DBG_WARN_AND_RETURN_VOID_UNLESS(m_pCbbSpec, L"m_pCbbSpec为空", L"GMEP", L"2024-01-30");
        m_pCbbSpec->clear();
        QStringList specs;
        for (auto spec : m_context->GetActiveSpecifications())
        {
            specs << QString::fromStdWString(spec);
        }
        m_pCbbSpec->addItems(specs);

        std::wstring currentSpec = m_context->GetCurrentSpecificationName();
        m_pCbbSpec->setCurrentText(QString::fromStdWString(currentSpec));
        
        DBG_WARN_AND_RETURN_VOID_UNLESS(m_pGeoParametersTable, L"m_pGeoParametersTable为空", L"GMEP", L"2024-01-30");
        m_pGeoParametersTable->SetParameters(m_context->GetActiveGeometyParameters(currentSpec));
        DBG_WARN_AND_RETURN_VOID_UNLESS(pStandardParametersCard, L"pStandardParametersCard为空", L"GMEP", L"2024-01-30");
        pStandardParametersCard->SetParameters(m_context->GetActiveStandardParameters(currentSpec));
     //   pCustomParametersCard->SetParameters(m_context->GetActiveCustomParameters(currentSpec));

        DBG_WARN_AND_RETURN_VOID_UNLESS(m_pBtnRenameSpec, L"m_pBtnRenameSpec为空", L"GMEP", L"2024-01-30");
        m_pBtnRenameSpec->setEnabled(m_context->GetActiveSpecifications().size() >= 1);
        DBG_WARN_AND_RETURN_VOID_UNLESS(m_pBtnDeleteSpec, L"m_pBtnDeleteSpec为空", L"GMEP", L"2024-01-30");
        m_pBtnDeleteSpec->setEnabled(m_context->GetActiveSpecifications().size() >= 2);
    }

    void ProjectComponentEditingPage::PopulateLegends()
    {
        if (!m_context)
        {
            return;
        }

        std::shared_ptr<ILegend> spPlanLegend = m_context->GetActiveLegend(ILegend::LegendType::Plan);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pPlanLegendCard != nullptr, L"pPlanLegendCard为空", L"GMEP", L"2024-01-30");
        pPlanLegendCard->SetLegend(spPlanLegend);

        std::shared_ptr<ILegend> spElevationLegend = m_context->GetActiveLegend(ILegend::LegendType::Elevation);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pElevationLegendCard != nullptr, L"pElevationLegendCard为空", L"GMEP", L"2024-01-30");
        pElevationLegendCard->SetLegend(spElevationLegend);

        std::shared_ptr<ILegend> spProfileLegend = m_context->GetActiveLegend(ILegend::LegendType::Profile);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pProfileLegendCard != nullptr, L"pProfileLegendCard为空", L"GMEP", L"2024-01-30");
        pProfileLegendCard->SetLegend(spProfileLegend);
        
        std::shared_ptr<ILegend> spElectricLegend = m_context->GetActiveLegend(ILegend::LegendType::Electric);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pElectricLegendCard != nullptr, L"pElectricLegendCard为空", L"GMEP", L"2024-01-30");
        pElectricLegendCard->SetLegend(spElectricLegend);
        
    }

    void ProjectComponentEditingPage::Populate3DView()
    {
        if (!m_context)
        {
            return;
        }
        //m_context->Stage(m_context->GetCurrentSpecificationName());
        
        auto currentSpec = m_context->GetCurrentSpecificationName();
        auto geometryParameters = m_context->GetActiveGeometyParameters(currentSpec);
        auto geometryParametersStr = std::wstring();
        for (auto &geoParam : geometryParameters)
        {
            if (geoParam && geoParam->Definition && geoParam->Definition->GetParameterType() == L"Double")
            {
                if (!geometryParametersStr.empty())
                {
                    geometryParametersStr += L";";
                }

                geometryParametersStr += geoParam->Definition->GetName() + L"=" + geoParam->Value;
            }
        }
        DBG_WARN_AND_RETURN_VOID_UNLESS(m_pGac3DViewer != nullptr, L"m_pGac3DViewer为空", L"GMEP", L"2024-01-30");
        m_pGac3DViewer->DisplayAsync(m_context->GetComponentLocalFilePath(), geometryParametersStr);
    }

    void ProjectComponentEditingPage::UpdateVisableByIsCommand()
    {
        if (m_pCbbSpec)
        {
            m_pCbbSpec->setEnabled(!m_isByCommandShow);
        }

        if (m_pBtnCreateNewSpec)
        {
            m_pBtnCreateNewSpec->setVisible(!m_isByCommandShow);
        }

        if (m_pBtnRenameSpec)
        {
            m_pBtnRenameSpec->setVisible(!m_isByCommandShow);
        }

        if (m_pBtnDeleteSpec)
        {
            m_pBtnDeleteSpec->setVisible(!m_isByCommandShow);
        }
    }

    void gmepgcs::ProjectComponentEditingPage::UpdateAfterSave(std::shared_ptr<IProjectComponent> savedComponent)
    {
        if (!m_context)
        {
            return;
        }

        if (!savedComponent)
        {
            return;
        }

        ProjectComponentWorkflowBase *pUpdateWorkflow = nullptr;
        if (AppService::IsGmep())
        {
            pUpdateWorkflow = SyncLocalProjectComponentWorkflow::Create(ProjectComponentWorkflowArgument(m_context->GetProjectId(), savedComponent->Id, savedComponent->Version, savedComponent->Name), this);
        }
        

        BnufBulletin::SingleShooting(GBMP_TR(L"正在更新"), BnufBulletin::BulletinIcon::Waiting, [=](BnufBulletin *bulletin) {
            if (!bulletin)
            {
                return;
            }
            DBG_WARN_AND_RETURN_VOID_UNLESS(pUpdateWorkflow, L"pUpdateWorkflow为空", L"GMEP", L"2024-01-30");
            WorkflowBase* pWorkflowBaseOfSuccess = pUpdateWorkflow
                ->OnSuccess([=](const std::wstring message) {
                bulletin->close();
                BnufBulletin::SingleShot(GBMP_TR(L"保存并更新成功"), BnufBulletin::BulletinIcon::Success, 500, nullptr, [=]() {
                    emit EditingFinished(m_context->GetProjectId(), savedComponent->Id, savedComponent->Version, m_isByCommandShow);
                });

                return;
            });
            DBG_WARN_AND_RETURN_VOID_UNLESS(pWorkflowBaseOfSuccess, L"pWorkflowBaseOfSuccess为空", L"GMEP", L"2024-01-30");
            WorkflowBase* pWorkflowBaseOfFail = pWorkflowBaseOfSuccess->OnFail([=](const std::wstring message) {
                bulletin->close();
               
                gnuf::ShowMessageBoard(GBMP_TR(L"保存修改成功，但更新至当前工作单元失败，请尝试手动更新！"), GBMP_TR(L"提示"), gnuf::eMB_OK | gnuf::eMB_ICONWARNING);
                emit EditingFinished(m_context->GetProjectId(), savedComponent->Id, savedComponent->Version, m_isByCommandShow);
                return;
            });
            DBG_WARN_AND_RETURN_VOID_UNLESS(pWorkflowBaseOfFail, L"pWorkflowBaseOfFail为空", L"GMEP", L"2024-01-30");
            WorkflowBase* pWorkflowBaseOfReport = pWorkflowBaseOfFail->OnReport([=](const std::wstring message) {
                bulletin->ConfigIcon(BnufBulletin::BulletinIcon::Waiting)->ConfigMessage(message);
            });
            DBG_WARN_AND_RETURN_VOID_UNLESS(pWorkflowBaseOfReport, L"pWorkflowBaseOfReport为空", L"GMEP", L"2024-01-30");
            pWorkflowBaseOfReport->Proceed(true);
        });
    }

}